using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

using config = Microsoft.ConnectionEngine.SampleDeploymentManager.Configuration;
using pages = Microsoft.ConnectionEngine.SampleDeploymentManager.WizardPages;

namespace Microsoft.ConnectionEngine.SampleDeploymentManager
{
    public partial class Main : Form
    {
        private const string PROD_NAME = "productName";
        private const string APP_NAME = "applicationName";
        private const string SRC_FOLDER = "sourceFolder";
        private const string DEST_FOLDER = "destinationFolder";
        private const string SA_SUB_FOLDER = "saSubFolder";
        private const string SP_SUB_FOLDER = "spSubFolder";
        private const string SA_ENCRYPT_KEY_FOLDER = "saEncryptKeyFolder";
        private const string SA_CONFIG_FILE = "saConfigFile";
        private const string SP_CONFIG_FILE = "spConfigFile";

        private const string APP_IIS_SITE = "appIISSite";
        private const string APP_POOL_NAME = "appPoolName";

        private const string SPR_DB_NAME = "sprDBName";
        private const string SPR_DB_USER = "sprDBUser";

        private const string ERROR_MESSAGE = "errorMessage";

        private const string DEFAULT_APP_TITLE = "Deployment Manager";

        private const string DEFAULT_SPR_DB_NAME = "ServiceProviderRegister";
        private const string DEFAULT_SPR_DB_USER = "SPRUser";

        private const string DEFAULT_APP_POOL_NAME = "ConnectionEngineAppPool";

        private bool showCloseWarning = true;
        private config.WizardPageConfig currentWizardPageConfig = null;
        private Dictionary<string, object> parameters = new Dictionary<string, object>();

        public Main()
        {
            InitializeComponent();

            try
            {
                LoadConfigSettings();
            }
            catch (Exception ex)
            {
                parameters.Add(ERROR_MESSAGE, ex.Message);
                currentWizardPageConfig = config.ConfigurationManager.WizardPages[config.ConfigurationManager.CancelPageName];
            }

            ShowNextWizardPage();
        }

        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.currentWizardPageConfig.IsProcessingPage)
            {
                e.Cancel = true;
            }
            else if (this.showCloseWarning)
            {
                YesNoDialog dialog = new YesNoDialog("The installation is not yet complete. Are you sure you want to exit?");
                dialog.Text = this.Text;

                e.Cancel = true;
                
                if (dialog.ShowDialog(this) == DialogResult.Yes)
                {
                    currentWizardPageConfig = config.ConfigurationManager.WizardPages[config.ConfigurationManager.CancelPageName];
                    ShowWizardPage();
                }
            }
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnBack_Click(object sender, EventArgs e)
        {
            ShowPreviousWizardPage();
        }

        private void btnNext_Click(object sender, EventArgs e)
        {
            if (this.currentWizardPageConfig.IsClosePage)
            {
                this.Close();
            }
            else
            {
                ShowNextWizardPage();
            }
        }

        private void WizardPage_Error(object sender, pages.ErrorEventArgs e)
        {
            currentWizardPageConfig = config.ConfigurationManager.WizardPages[config.ConfigurationManager.CancelPageName];

            parameters.Add(ERROR_MESSAGE, e.Message);
            ShowWizardPage();
        }

        private void WizardPage_Completed(object sender, EventArgs e)
        {
            btnNext_Click(sender, e);
        }

        private void LoadConfigSettings()
        {
            DirectoryInfo dirInfo;

            string productName = System.Configuration.ConfigurationManager.AppSettings["ProductName"].ToString();
            string applicationName = System.Configuration.ConfigurationManager.AppSettings["ApplicationName"].ToString();
            
            string sourceFolder = System.Configuration.ConfigurationManager.AppSettings["SourceFolder"].ToString();
            
            string destinationFolder = System.Configuration.ConfigurationManager.AppSettings["DefaultDestinationFolder"].ToString();
            string webServiceAppName = System.Configuration.ConfigurationManager.AppSettings["DefaultWebServiceApplicationName"].ToString();

            string saSubFolder = System.Configuration.ConfigurationManager.AppSettings["SASubFolder"].ToString();
            string spSubFolder = System.Configuration.ConfigurationManager.AppSettings["SPSubFolder"].ToString();
            string saEncryptKeySubFolder = System.Configuration.ConfigurationManager.AppSettings["SAEncryptKeySubFolder"].ToString();
            string saConfigFile = System.Configuration.ConfigurationManager.AppSettings["SAConfigFile"].ToString();
            string spConfigFile = System.Configuration.ConfigurationManager.AppSettings["SPConfigFile"].ToString();

            sourceFolder = Utilities.MapPath(sourceFolder);
            destinationFolder = Utilities.MapPath(destinationFolder);
            
            parameters.Add(PROD_NAME, productName);
            parameters.Add(APP_NAME, applicationName);

            if (productName.Length > 0)
            {
                this.Text = productName + " " + DEFAULT_APP_TITLE;
            }
            else
            {
                this.Text = DEFAULT_APP_TITLE;
            }

            dirInfo = new DirectoryInfo(sourceFolder);
            if (!dirInfo.Exists)
            {
                throw new DirectoryNotFoundException(string.Format("Deployment source folder ({0}) not found", dirInfo.FullName));
            }

            if (saSubFolder.Length > 0)
            {
                if (Path.IsPathRooted(saSubFolder))
                {
                    throw new Exception(String.Format("Deployment source folder for the system adapter ({0}) is not a relative path", saSubFolder));
                }
                else
                {
                    dirInfo = new DirectoryInfo(Path.Combine(sourceFolder, saSubFolder));
                }

                if (!dirInfo.Exists)
                {
                    throw new DirectoryNotFoundException(string.Format("Deployment source folder for the system adapter ({0}) not found", dirInfo.FullName));
                }
            }
            else
            {
                throw new DirectoryNotFoundException("The system adapter source folder name has not been defined");
            }
            if (!saSubFolder.EndsWith("\\")) saSubFolder += "\\";

            if (spSubFolder.Length > 0)
            {
                if (Path.IsPathRooted(spSubFolder))
                {
                    throw new Exception(String.Format("Deployment source folder for the service provider ({0}) is not a relative path", spSubFolder));
                }
                else
                {
                    dirInfo = new DirectoryInfo(Path.Combine(sourceFolder, spSubFolder));
                }

                if (!dirInfo.Exists)
                {
                    throw new DirectoryNotFoundException(string.Format("Deployment source folder for the service provider ({0}) not found", dirInfo.FullName));
                }
            }
            else
            {
                throw new DirectoryNotFoundException("The service provider source folder name has not been defined");
            }
            if (!spSubFolder.EndsWith("\\")) spSubFolder += "\\";

            if (saEncryptKeySubFolder.Length > 0)
            {
                if (Path.IsPathRooted(saEncryptKeySubFolder))
                {
                    throw new Exception(String.Format("The destination encryption key folder for the system adapter ({0}) is not a relative path", saEncryptKeySubFolder));
                }
                else
                {
                    saEncryptKeySubFolder = saSubFolder + saEncryptKeySubFolder;
                }

                if (!saEncryptKeySubFolder.EndsWith("\\")) saEncryptKeySubFolder += "\\";
            }

            dirInfo = new DirectoryInfo(destinationFolder);
            if (dirInfo.Exists)
            {
                string originalDestination = dirInfo.FullName;
                if (originalDestination.EndsWith("\\")) originalDestination = originalDestination.Substring(0, originalDestination.Length - 1);

                int index = 1;
                while (dirInfo.Exists)
                {
                    string newFolder = originalDestination + index.ToString();

                    dirInfo = new DirectoryInfo(newFolder);
                    index++;
                }

                destinationFolder = dirInfo.FullName;
            }
            destinationFolder = dirInfo.FullName;
            if (!destinationFolder.EndsWith("\\")) destinationFolder += "\\";

            if (saConfigFile.Length > 0)
            {
                dirInfo = new DirectoryInfo(Path.Combine(sourceFolder, saSubFolder));
                FileInfo fileInfo = new FileInfo(Path.Combine(dirInfo.FullName, saConfigFile));
                if (!fileInfo.Exists)
                {
                    throw new FileNotFoundException(string.Format("The system adapter source folder ({0}) does not contain a config file ({1})", saSubFolder, saConfigFile));
                }
            }
            else
            {
                throw new FileNotFoundException("The system adapter source config file name has not been defined");
            }
            saConfigFile = saSubFolder + saConfigFile;

            if (spConfigFile.Length > 0)
            {
                dirInfo = new DirectoryInfo(Path.Combine(sourceFolder, spSubFolder));
                FileInfo fileInfo = new FileInfo(Path.Combine(dirInfo.FullName, spConfigFile));
                if (!fileInfo.Exists)
                {
                    throw new FileNotFoundException(string.Format("The service provider source folder ({0}) does not contain a config file ({1})", spSubFolder, spConfigFile));
                }
            }
            else
            {
                throw new FileNotFoundException("The service provider source config file name has not been defined");
            }
            spConfigFile = spSubFolder + spConfigFile;

            if (webServiceAppName.Length > 0)
            {
                string originalWebServiceAppName = webServiceAppName;

                int index = 1;
                while (Utilities.IISVirtualDirExists(Utilities.GetCurrentHostName(), webServiceAppName))
                {
                    webServiceAppName = originalWebServiceAppName + index.ToString();
                    index++;
                }
            }

            parameters.Add(SRC_FOLDER, sourceFolder);
            parameters.Add(DEST_FOLDER, destinationFolder);
            parameters.Add(SA_SUB_FOLDER, saSubFolder);
            parameters.Add(SP_SUB_FOLDER, spSubFolder);
            parameters.Add(SA_ENCRYPT_KEY_FOLDER, saEncryptKeySubFolder);
            parameters.Add(SA_CONFIG_FILE, saConfigFile);
            parameters.Add(SP_CONFIG_FILE, spConfigFile);

            parameters.Add(APP_IIS_SITE, webServiceAppName);
            parameters.Add(APP_POOL_NAME, DEFAULT_APP_POOL_NAME);

            parameters.Add(SPR_DB_NAME, DEFAULT_SPR_DB_NAME);
            parameters.Add(SPR_DB_USER, DEFAULT_SPR_DB_USER);
        }

        private void ShowPreviousWizardPage()
        {
            if (this.currentWizardPageConfig == null)
            {
                this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[0];
            }
            else
            {
                if (this.currentWizardPageConfig.PreviousPageName.Length > 0)
                {
                    this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[this.currentWizardPageConfig.PreviousPageName];
                }
                else
                {
                    this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[0];
                }
            }

            ShowWizardPage();
        }

        private void ShowNextWizardPage()
        {
            if (this.currentWizardPageConfig == null)
            {
                this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[0];
            }
            else
            {
                if (this.currentWizardPageConfig.NextPageName.Length > 0)
                {
                    this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[this.currentWizardPageConfig.NextPageName];
                }
                else
                {
                    this.currentWizardPageConfig = config.ConfigurationManager.WizardPages[config.ConfigurationManager.WizardPages.Count - 1];
                }
            }

            ShowWizardPage();
        }

        private void ShowWizardPage()
        {
            pages.WizardPageBase wizardPage = (pages.WizardPageBase)ReflectionSupport.CreateInstance(this.currentWizardPageConfig.Type);

            lblTitle.Text = this.currentWizardPageConfig.Title;

            wizardPage.Error += new pages.ErrorEventHandler(this.WizardPage_Error);
            wizardPage.Complete += new EventHandler(this.WizardPage_Completed);

            if (this.currentWizardPageConfig.IsClosePage) btnNext.Text = "&Close";
            btnCancel.Enabled = (!this.currentWizardPageConfig.IsProcessingPage && !this.currentWizardPageConfig.IsClosePage);
            btnBack.Enabled = (!this.currentWizardPageConfig.IsProcessingPage && !(this.currentWizardPageConfig.PreviousPageName.Length == 0 || this.currentWizardPageConfig.IsClosePage));
            btnNext.Enabled = (!this.currentWizardPageConfig.IsProcessingPage);
            if (btnNext.Enabled) btnNext.Focus();

            this.showCloseWarning = !(this.currentWizardPageConfig.IsClosePage);

            pnlMain.Controls.Clear();
            pnlMain.Controls.Add(wizardPage);

            Application.DoEvents();
            wizardPage.Activate(ref parameters);
        }
    }
}